﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Cci;
using SpCop.Core;
using SpCop.Core.Model;
using SpCop.Model;

namespace SpCop
{
    public class RuleBase : IVisitor<Package>, IVisitor<Feature>, IVisitor<Element>, IRule
    {
        protected internal Package Package;
        protected internal List<Problem> Problems;
        public RuleDefinition Rule;
        private static readonly XName _fileXName = XName.Get("File", "http://schemas.microsoft.com/sharepoint/");

        #region IRule Members

        public virtual IList<Problem> Check(Package package)
        {
            Problems = new List<Problem>();

            Package = package;

            return Problems;
            
        }

        #endregion

        #region IVisitor<Element> Members

        public virtual void Visit(Element item)
        {
        }

        #endregion

        #region IVisitor<Feature> Members

        public virtual void Visit(Feature item)
        {
            VisitCollection(item.Elements, Visit);
        }

        #endregion

        #region IVisitor<Package> Members

        public virtual void Visit(Package item)
        {
            VisitCollection(item.Features, Visit);
        }

        #endregion

        public static void VisitCollection<TItem>(IEnumerable<TItem> item, Action<TItem> action)
        {
            foreach (TItem item1 in item)
            {
                action(item1);
            }

            //var tasks = item.Select(a => Task.Factory.StartNew(()=>action(a))).ToArray();
            //Task.WaitAll(tasks);
        }


        protected Resolution GetResolution(string name, params string[] args)
        {
            
            var resolution = Rule.Resolutions.SingleOrDefault(a => a.Name == name);
            return resolution != null
                       ? new Resolution(resolution.Value, args)
                       : new Resolution("The resolution with name '{0}' was not found ! ", name);
        }

        protected void AddProblem(Problem problem)
        {
            Problems.Add(problem);
        }

        protected void AddProblem(string resolutionName, params string[] args)
        {
            AddProblem(new Problem(GetResolution(resolutionName, args)));
        }


        protected INamedTypeDefinition GetReceiverTypeNode(Feature item)
        {
            if (item.ReveiverType == null)
            {
                var indexOfComma = item.ReceiverTypeName.IndexOf(",");
                if(indexOfComma == -1 || indexOfComma + 1 > item.ReceiverTypeName.Length)
                    throw new ArgumentOutOfRangeException("item.ReveiverType");

                string assemblyName = item.ReceiverTypeName.Substring(indexOfComma + 1).Trim();

                var indexOf = assemblyName.IndexOf(",");

                if (indexOf == -1 || indexOf > assemblyName.Length)
                    throw new ArgumentOutOfRangeException("item.ReveiverType");


                string net = assemblyName.Substring(0, indexOf);

                string typeNmae = item.ReceiverTypeName.Substring(0, indexOfComma);


                IModule assemblyNode = item.Package.Modules.SingleOrDefault(a => a.Name.ToString() == net);

                if(assemblyNode == null || assemblyNode.ContainingAssembly == null)
                    throw new FileNotFoundException("Could not load Feature receiver type.");

                INamespaceTypeDefinition[] types =
                    assemblyNode.ContainingAssembly.GetAllTypes().OfType<INamespaceTypeDefinition>().ToArray();

                item.ReveiverType = types.SingleOrDefault(a => a.ToString() == typeNmae);
                return item.ReveiverType;
            }
            else
            {
                return item.ReveiverType;
            }
        }

        protected MixedContentFile GetParsedContentFile(string path)
        {
           
            
            string dataPage = File.ReadAllText(path);
            
            return MixedContentFile.Parse(dataPage);
        }

        protected IEnumerable<XElement> GetFileElements(XElement moduleElement)
        {
           
            return GetFileElements(moduleElement, "");
        }

        protected IEnumerable<XElement> GetFileElements(XElement moduleElement, string extension)
        {
           
            var files =
                moduleElement.Descendants(_fileXName);
            if (!string.IsNullOrEmpty(extension))
            {
                string upperInvariant = extension.ToUpperInvariant();
                files =
                    files.Where(
                        a =>
                        a != null && a.Attribute("Url") != null &&
                        Convert.ToString(a.Attribute("Url").Value).ToUpperInvariant().EndsWith(upperInvariant));
            }
            return files;
        }
    }
}